/**
 * 
 */
package com.upstairstechnology.oi.notification;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang.IllegalClassException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import com.upstairstechnology.oi.notification.console.NotificationStrategyConsole;
import com.upstairstechnology.oi.notification.email.NotificationConfigurationEmail;
import com.upstairstechnology.oi.notification.email.NotificationStrategyEmail;
import com.upstairstechnology.oi.notification.email.resolver.EmailResolver;

/**
 * Default factory implementation for creating NotificationStrategys.
 * 
 * @author Jeff Jensen
 */
public class NotificationStrategyFactoryDefault implements
        NotificationStrategyFactory {
    /** Logger instance. */
    private static final Logger LOGGER =
            LoggerFactory.getLogger(NotificationStrategyFactoryDefault.class);

    /** Class names of configured notification strategies. */
    private String[] notificationStrategies;

    private NotificationConfigurationEmail emailConfiguration;

    private EmailResolver emailResolver;

    /**
     * Make an empty set of notification strategies.
     * 
     * @return An empty set of notification strategies.
     */
    public Set<NotificationStrategy> makeEmptySet() {
        return new HashSet<NotificationStrategy>();
    }

    /**
     * {@inheritDoc}
     */
    public Set<NotificationStrategy> makeNotifications()
            throws ClassNotFoundException, InstantiationException,
            IllegalAccessException {
        LOGGER.debug("notificationArray={}", notificationStrategies);

        final Set<NotificationStrategy> strategySet = makeEmptySet();

        for (String strategyString : notificationStrategies) {
            strategyString = strategyString.trim();
            LOGGER.debug("Making NotificationStrategy={}", strategyString);

            Class<?> clazz = Class.forName(strategyString);
            NotificationStrategy strategy =
                    (NotificationStrategy) clazz.newInstance();
            populateStrategy(strategy);

            strategySet.add(strategy);
        }

        return strategySet;
    }

    /**
     * Set configuration objects on the notification strategy as needed for the
     * implementation class.
     * 
     * @param strategy
     *            Strategy to populate with configuration objects.
     */
    protected void populateStrategy(NotificationStrategy strategy) {
        // TODO how to set these without using instanceof?
        if (strategy instanceof NotificationStrategyEmail) {
            LOGGER.debug("Determined strategy is of type email");
            NotificationStrategyEmail emailStrategy =
                    (NotificationStrategyEmail) strategy;
            emailStrategy.setEmailConfiguration(emailConfiguration);
            emailStrategy.setEmailResolver(emailResolver);
        } else if (strategy instanceof NotificationStrategyConsole) {
            LOGGER.debug("Determined strategy is of type console");
            NotificationStrategyConsole consoleStrategy =
                    (NotificationStrategyConsole) strategy;
            // TODO need to implement "consoleConfiguration"?
            LOGGER.error("IMPLEMENT ME");
        } else {
            final String msg =
                    "Unsupported NotificationStrategy='"
                            + strategy.getClass().getCanonicalName()
                            + "'.  If it is a new strategy type,"
                            + " then update this method to support it.";
            throw new IllegalClassException(msg);
        }
    }

    /**
     * Get the notificationStrategies.
     * 
     * @see {@link notificationStrategies}.
     * 
     * @return The notificationStrategies.
     */
    public String[] getNotificationStrategies() {
        return notificationStrategies;
    }

    /**
     * Set the notificationStrategies.
     * 
     * @see {@link notificationStrategies}.
     * 
     * @param strategies
     *            The notification strategies to set.
     */
    @Required
    public void setNotificationStrategies(String[] strategies) {
        this.notificationStrategies = strategies;
    }

    /**
     * {@inheritDoc}
     */
    @Required
    public NotificationConfigurationEmail getEmailConfiguration() {
        return emailConfiguration;
    }

    /**
     * {@inheritDoc}
     */
    @Required
    public void setEmailConfiguration(NotificationConfigurationEmail cfg) {
        this.emailConfiguration = cfg;
    }

    /**
     * {@inheritDoc}
     */
    public EmailResolver getEmailResolver() {
        return emailResolver;
    }

    /**
     * {@inheritDoc}
     */
    public void setEmailResolver(EmailResolver resolver) {
        this.emailResolver = resolver;
    }
}
